// 解析指令的类  
class Compiler {
  constructor(vm) {
    this.el = vm.$el
    this.vm = vm
    //解析指令的具体函数
    this.compiler(vm.$el)
  }
  compiler(el) {
    //取出所有子节点
    //区分节点的属性 调用不同的处理函数 
    //是否有嵌套节点 递归调用  
    let childNodes = el.childNodes
    Array.from(childNodes).forEach(ele => {
      //  nodeType 1:元素节点 3：文本节点  
      if (ele.nodeType == 1) {
        this.compileElement(ele)
      } else if (ele.nodeType == 3) {
        this.compileText(ele)
      }
      if (ele.childNodes && ele.childNodes.length) {
        this.compiler(ele)
      }
    })
  }
  //处理元素节点  主要是解析属性里的指令
  compileElement(el) {
    Array.from(el.attributes).forEach(attr => {
      // 这里的每一个属性都会是一个对象  name 是名字  value是值
      let attername = attr.name
      if (this.isDirective(attername)) {
        let key = attername.substr(2)
        let attrName = attr.value
        this.update(el, key, attrName)

      }
    })
  }
  //v-text  v-model
  update(node, key, attrName) {
    let updateFn = this[key + 'updataer']
    updateFn && updateFn.call(this, node, this.vm[attrName], attrName,)
  }
  textupdataer(node, value, key) {
    node.textContent = value
    //创建观察者 
    new Watcher(this.vm, key, value => {
      node.textContent = value
    })
  }
  modelupdataer(node, value, key) {
    node.value = value
    node.addEventListener('input', value => {
      //事件监听
      this.vm[key] = node.value
    })
    //创建观察者 
    new Watcher(this.vm, key, value => {
      node.value = value
    })
  }
  htmlUpdate(node, value, key) {
    node.innerHTML = value
    new Watcher(this.vm, key, newValue => {
      node.innerHTML = newValue
    })
  }
  onUpdate(node, value, key, eventName) {
    node.addEventListener(eventName, () => {
      let enentFn = this.vm.$options.methods[key]
      if (enentFn) {
        enentFn.call(this)
      } else {
        eval(key)
      }
    })
  }

  // 处理文本节点  {{ msg }} 传过来的节点是文本
  // ？？？ nodevalue 与textContent 的区别 
  compileText(node) {
    let reg = /\{\{(.+?)\}\}/
    if (reg.test(node.nodeValue)) {
      let key = RegExp.$1.trim()  //记得去掉两端的空格
      node.textContent = this.vm[key]
      //创建观察者 
      new Watcher(this.vm, key, value => {
        node.textContent = value
      })
    }
  }

  isDirective(attr) {
    return attr.startsWith('v-')
  }
}